package com.ltx.bugseeker.utils;

import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.regex.Pattern;

/**
 * 统一业务校验工具类
 * 提供各种常用的数据格式校验方法，包括手机号、身份证、邮箱等
 * 
 * @author ltx
 * @since 2025-10-20 14:43:42
 */
@Slf4j
public class ValidationUtils {
    
    /**
     * 手机号正则表达式
     * 支持中国大陆手机号格式：13x, 14x, 15x, 16x, 17x, 18x, 19x
     */
    private static final String MOBILE_REGEX = "^1[3-9]\\d{9}$";
    
    /**
     * 邮箱正则表达式
     * 标准邮箱格式校验
     */
    private static final String EMAIL_REGEX = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
    
    /**
     * 身份证号正则表达式（18位）
     * 支持18位身份证号码格式
     */
    private static final String ID_CARD_REGEX = "^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$";
    
    /**
     * 用户名正则表达式
     * 支持字母、数字、下划线，长度3-20位
     */
    private static final String USERNAME_REGEX = "^[a-zA-Z0-9_]{3,20}$";
    
    /**
     * 密码强度正则表达式
     * 至少包含字母和数字，长度6-20位
     */
    private static final String PASSWORD_REGEX = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d@$!%*#?&]{6,20}$";
    
    /**
     * IP地址正则表达式
     * 支持IPv4格式
     */
    private static final String IP_REGEX = "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$";
    
    /**
     * URL正则表达式
     * 支持http和https协议
     */
    private static final String URL_REGEX = "^(https?://)?(www\\.)?[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*(/.*)?$";
    
    /**
     * 中文姓名正则表达式
     * 支持2-10个中文字符
     */
    private static final String CHINESE_NAME_REGEX = "^[\\u4e00-\\u9fa5]{2,10}$";
    
    /**
     * 编译后的正则表达式模式
     */
    private static final Pattern MOBILE_PATTERN = Pattern.compile(MOBILE_REGEX);
    private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_REGEX);
    private static final Pattern ID_CARD_PATTERN = Pattern.compile(ID_CARD_REGEX);
    private static final Pattern USERNAME_PATTERN = Pattern.compile(USERNAME_REGEX);
    private static final Pattern PASSWORD_PATTERN = Pattern.compile(PASSWORD_REGEX);
    private static final Pattern IP_PATTERN = Pattern.compile(IP_REGEX);
    private static final Pattern URL_PATTERN = Pattern.compile(URL_REGEX);
    private static final Pattern CHINESE_NAME_PATTERN = Pattern.compile(CHINESE_NAME_REGEX);
    
    /**
     * 身份证号码校验位权重
     */
    private static final int[] ID_CARD_WEIGHTS = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
    
    /**
     * 身份证号码校验位对应字符
     */
    private static final char[] ID_CARD_CHECK_CODES = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
    
    /**
     * 校验手机号格式
     * 
     * @param mobile 手机号码
     * @return true表示格式正确，false表示格式错误
     */
    public static boolean isValidMobile(String mobile) {
        if (StrUtil.isBlank(mobile)) {
            return false;
        }
        return MOBILE_PATTERN.matcher(mobile.trim()).matches();
    }
    
    /**
     * 校验邮箱格式
     * 
     * @param email 邮箱地址
     * @return true表示格式正确，false表示格式错误
     */
    public static boolean isValidEmail(String email) {
        if (StrUtil.isBlank(email)) {
            return false;
        }
        return EMAIL_PATTERN.matcher(email.trim().toLowerCase()).matches();
    }
    
    /**
     * 校验身份证号码格式和校验位
     * 
     * @param idCard 身份证号码
     * @return true表示格式正确，false表示格式错误
     */
    public static boolean isValidIdCard(String idCard) {
        if (StrUtil.isBlank(idCard)) {
            return false;
        }
        
        String trimmedIdCard = idCard.trim().toUpperCase();
        
        // 格式校验
        if (!ID_CARD_PATTERN.matcher(trimmedIdCard).matches()) {
            return false;
        }
        
        // 校验位计算
        return isValidIdCardCheckCode(trimmedIdCard);
    }
    
    /**
     * 校验用户名格式
     * 
     * @param username 用户名
     * @return true表示格式正确，false表示格式错误
     */
    public static boolean isValidUsername(String username) {
        if (StrUtil.isBlank(username)) {
            return false;
        }
        return USERNAME_PATTERN.matcher(username.trim()).matches();
    }
    
    /**
     * 校验密码强度
     * 
     * @param password 密码
     * @return true表示强度符合要求，false表示强度不够
     */
    public static boolean isValidPassword(String password) {
        if (StrUtil.isBlank(password)) {
            return false;
        }
        return PASSWORD_PATTERN.matcher(password).matches();
    }
    
    /**
     * 校验IP地址格式
     * 
     * @param ip IP地址
     * @return true表示格式正确，false表示格式错误
     */
    public static boolean isValidIp(String ip) {
        if (StrUtil.isBlank(ip)) {
            return false;
        }
        return IP_PATTERN.matcher(ip.trim()).matches();
    }
    
    /**
     * 校验URL格式
     * 
     * @param url URL地址
     * @return true表示格式正确，false表示格式错误
     */
    public static boolean isValidUrl(String url) {
        if (StrUtil.isBlank(url)) {
            return false;
        }
        return URL_PATTERN.matcher(url.trim()).matches();
    }
    
    /**
     * 校验中文姓名格式
     * 
     * @param name 中文姓名
     * @return true表示格式正确，false表示格式错误
     */
    public static boolean isValidChineseName(String name) {
        if (StrUtil.isBlank(name)) {
            return false;
        }
        return CHINESE_NAME_PATTERN.matcher(name.trim()).matches();
    }
    
    /**
     * 校验字符串长度范围
     * 
     * @param str 待校验字符串
     * @param minLength 最小长度
     * @param maxLength 最大长度
     * @return true表示长度符合要求，false表示长度不符合要求
     */
    public static boolean isValidLength(String str, int minLength, int maxLength) {
        if (str == null) {
            return minLength <= 0;
        }
        int length = str.length();
        return length >= minLength && length <= maxLength;
    }
    
    /**
     * 校验数字范围
     * 
     * @param number 待校验数字
     * @param min 最小值
     * @param max 最大值
     * @return true表示数字在范围内，false表示数字超出范围
     */
    public static boolean isValidRange(Number number, Number min, Number max) {
        if (number == null) {
            return false;
        }
        double value = number.doubleValue();
        double minValue = min.doubleValue();
        double maxValue = max.doubleValue();
        return value >= minValue && value <= maxValue;
    }
    
    /**
     * 校验是否为正整数
     * 
     * @param str 待校验字符串
     * @return true表示是正整数，false表示不是正整数
     */
    public static boolean isPositiveInteger(String str) {
        if (StrUtil.isBlank(str)) {
            return false;
        }
        return ReUtil.isMatch("^[1-9]\\d*$", str.trim());
    }
    
    /**
     * 校验是否为非负整数（包括0）
     * 
     * @param str 待校验字符串
     * @return true表示是非负整数，false表示不是非负整数
     */
    public static boolean isNonNegativeInteger(String str) {
        if (StrUtil.isBlank(str)) {
            return false;
        }
        return ReUtil.isMatch("^(0|[1-9]\\d*)$", str.trim());
    }
    
    /**
     * 校验是否为数字（包括小数）
     * 
     * @param str 待校验字符串
     * @return true表示是数字，false表示不是数字
     */
    public static boolean isNumber(String str) {
        if (StrUtil.isBlank(str)) {
            return false;
        }
        return ReUtil.isMatch("^-?\\d+(\\.\\d+)?$", str.trim());
    }
    
    /**
     * 校验银行卡号格式
     * 
     * @param bankCard 银行卡号
     * @return true表示格式正确，false表示格式错误
     */
    public static boolean isValidBankCard(String bankCard) {
        if (StrUtil.isBlank(bankCard)) {
            return false;
        }
        String trimmed = bankCard.trim().replaceAll("\\s", "");
        // 银行卡号通常为16-19位数字
        return ReUtil.isMatch("^\\d{16,19}$", trimmed);
    }
    
    /**
     * 校验车牌号格式
     * 
     * @param licensePlate 车牌号
     * @return true表示格式正确，false表示格式错误
     */
    public static boolean isValidLicensePlate(String licensePlate) {
        if (StrUtil.isBlank(licensePlate)) {
            return false;
        }
        String trimmed = licensePlate.trim().toUpperCase();
        // 支持新能源车牌和普通车牌
        return ReUtil.isMatch("^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-Z0-9]{4}[A-Z0-9挂学警港澳]$", trimmed) ||
               ReUtil.isMatch("^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-Z0-9]{5}[A-Z0-9]$", trimmed);
    }
    
    /**
     * 校验身份证号码校验位是否正确
     * 
     * @param idCard 18位身份证号码
     * @return true表示校验位正确，false表示校验位错误
     */
    private static boolean isValidIdCardCheckCode(String idCard) {
        try {
            int sum = 0;
            for (int i = 0; i < 17; i++) {
                sum += Character.getNumericValue(idCard.charAt(i)) * ID_CARD_WEIGHTS[i];
            }
            int checkCodeIndex = sum % 11;
            char expectedCheckCode = ID_CARD_CHECK_CODES[checkCodeIndex];
            char actualCheckCode = idCard.charAt(17);
            
            return expectedCheckCode == actualCheckCode;
        } catch (Exception e) {
            log.warn("身份证号码校验位计算异常: {}", idCard, e);
            return false;
        }
    }
    
    /**
     * 获取详细的校验错误信息
     * 
     * @param value 待校验值
     * @param type 校验类型
     * @return 错误信息，如果校验通过则返回null
     */
    public static String getValidationError(String value, ValidationType type) {
        if (StrUtil.isBlank(value)) {
            return type.getFieldName() + "不能为空";
        }
        
        boolean isValid = false;
        switch (type) {
            case MOBILE:
                isValid = isValidMobile(value);
                break;
            case EMAIL:
                isValid = isValidEmail(value);
                break;
            case ID_CARD:
                isValid = isValidIdCard(value);
                break;
            case USERNAME:
                isValid = isValidUsername(value);
                break;
            case PASSWORD:
                isValid = isValidPassword(value);
                break;
            case IP:
                isValid = isValidIp(value);
                break;
            case URL:
                isValid = isValidUrl(value);
                break;
            case CHINESE_NAME:
                isValid = isValidChineseName(value);
                break;
            case BANK_CARD:
                isValid = isValidBankCard(value);
                break;
            case LICENSE_PLATE:
                isValid = isValidLicensePlate(value);
                break;
        }
        
        return isValid ? null : type.getErrorMessage();
    }
    
    /**
     * 校验类型枚举
     */
    public enum ValidationType {
        MOBILE("手机号", "手机号格式不正确"),
        EMAIL("邮箱", "邮箱格式不正确"),
        ID_CARD("身份证号", "身份证号格式不正确"),
        USERNAME("用户名", "用户名格式不正确，只能包含字母、数字、下划线，长度3-20位"),
        PASSWORD("密码", "密码强度不够，至少包含字母和数字，长度6-20位"),
        IP("IP地址", "IP地址格式不正确"),
        URL("URL地址", "URL地址格式不正确"),
        CHINESE_NAME("中文姓名", "中文姓名格式不正确，应为2-10个中文字符"),
        BANK_CARD("银行卡号", "银行卡号格式不正确"),
        LICENSE_PLATE("车牌号", "车牌号格式不正确");
        
        private final String fieldName;
        private final String errorMessage;
        
        ValidationType(String fieldName, String errorMessage) {
            this.fieldName = fieldName;
            this.errorMessage = errorMessage;
        }
        
        public String getFieldName() {
            return fieldName;
        }
        
        public String getErrorMessage() {
            return errorMessage;
        }
    }
}